import { Body, Controller, Get, HttpService, Put, Query, Res } from '@nestjs/common';
import { Response } from 'express';
import OpenApi, * as $OpenApi from '@alicloud/openapi-client';
import Cms20190101, * as $Cms20190101 from '@alicloud/cms20190101';
import { ApiResult, ApiResultCode } from '../../common/api-result';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Server } from '../../server/server.entity';
import * as lodash from 'lodash';
import {
  PluginAliyunMonitorDto,
  PluginAliyunMonitorECSDto,
  PluginAliyunMonitorInstance,
  PluginAliyunMonitorPeriod,
  PluginAliyunMonitorPolardbDto,
  PluginAliyunMonitorRedisMetricDto, PluginAliyunMonitorRocketmqMetricDto,
  PluginAliyunMonitorSLBDto,
} from './plugin-aliyun-monitor.dto';
import { PluginAliyunSLB } from './plugin-aliyun-slb.entity';
import { PluginAliyunMonitorSLB_QPS } from './plugin-aliyun-monitor-slb-qps.entity';
import { PluginAliyunMonitorPolardbMetric } from './plugin-aliyun-monitor-polardb-metric.entity';
import { PluginAliyunPolardb } from './plugin-aliyun-polardb.entity';
import {
  PluginAliyunMonitorRedisMetric,
  PluginAliyunMonitorRedisMetricType,
} from './plugin-aliyun-monitor-redis-metric.entity';
import { PluginAliyunRedis } from './plugin-aliyun-redis.entity';
import {
  PluginAliyunMonitorRocketmqMetric,
  PluginAliyunMonitorRocketmqMetricType,
} from './plugin-aliyun-monitor-rocketmq-metric.entity';
import { PluginAliyunRocketmq } from './plugin-aliyun-rocketmq.entity';
import {
  PluginAliyunMonitorEcsMetric,
  PluginAliyunMonitorEcsMetricName,
} from './plugin-aliyun-monitor-ecs-metric.entity';

@Controller()
export class PluginAliyunMonitorController {

  constructor(
    @InjectRepository(Server)
    private serverRepository: Repository<Server>,
    @InjectRepository(PluginAliyunMonitorEcsMetric)
    private pluginAliyunMonitorEcsMetricRepository: Repository<PluginAliyunMonitorEcsMetric>,
    @InjectRepository(PluginAliyunSLB)
    private pluginAliyunSLBRepository: Repository<PluginAliyunSLB>,
    @InjectRepository(PluginAliyunMonitorSLB_QPS)
    private pluginAliyunMonitorSLBQPSRepository: Repository<PluginAliyunMonitorSLB_QPS>,
    @InjectRepository(PluginAliyunPolardb)
    private pluginAliyunPolardbRepository: Repository<PluginAliyunPolardb>,
    @InjectRepository(PluginAliyunMonitorPolardbMetric)
    private pluginAliyunMonitorPolardbQpsRepository: Repository<PluginAliyunMonitorPolardbMetric>,
    @InjectRepository(PluginAliyunRedis)
    private pluginAliyunRedisRepository: Repository<PluginAliyunRedis>,
    @InjectRepository(PluginAliyunMonitorRedisMetric)
    private pluginAliyunMonitorRedisMetricRepository: Repository<PluginAliyunMonitorRedisMetric>,
    @InjectRepository(PluginAliyunRocketmq)
    private pluginAliyunRocketmqRepository: Repository<PluginAliyunRocketmq>,
    @InjectRepository(PluginAliyunMonitorRocketmqMetric)
    private pluginAliyunMonitorRocketmqMetricRepository: Repository<PluginAliyunMonitorRocketmqMetric>,
  ) {
  }


  @Get('/api/plugin/monitor')
  async ecs(@Query() requestDto: PluginAliyunMonitorDto, @Res() res: Response) {

    const ar = new ApiResult();

    if (!requestDto.period) {
      return res.json(ApiResultCode['2']('周期不能为空'));
    }

    const responseDto = {} as PluginAliyunMonitorDto;
    responseDto.period = requestDto.period;

    const serverList = await this.serverRepository.find({ isMonitor: true });
    const pluginMonitorECSList: PluginAliyunMonitorInstance[] = serverList.map(value => ({
      instanceId: value.instanceId,
      instanceName: value.name,
    }));
    // ECS cpu_total
    const serverCpu_totalList: PluginAliyunMonitorEcsMetric[] = await this.pluginAliyunMonitorEcsMetricRepository.query(
      await this.packageSql(PluginAliyunMonitorEcsMetric.tableName, requestDto, pluginMonitorECSList,PluginAliyunMonitorEcsMetricName.cpu_total)
      ,
    );
    const pluginMonitorServerCpu_totalGroupByInstanceId = lodash.groupBy(serverCpu_totalList, value => value.instanceId);

    // ECS 内存使用率
    const serverMemory_usedutilizationList: PluginAliyunMonitorEcsMetric[] = await this.pluginAliyunMonitorEcsMetricRepository.query(
      await this.packageSql(PluginAliyunMonitorEcsMetric.tableName, requestDto, pluginMonitorECSList,PluginAliyunMonitorEcsMetricName.memory_usedutilization),
    );
    const pluginMonitorServerMemory_usedutilizationGroupByInstanceId = lodash.groupBy(serverMemory_usedutilizationList, value => value.instanceId);

    // ECS cpu_load
    const pluginMonitorServerCpuLoads: PluginAliyunMonitorEcsMetric[] = await this.pluginAliyunMonitorEcsMetricRepository.query(
      await this.packageSql(PluginAliyunMonitorEcsMetric.tableName, requestDto, pluginMonitorECSList,PluginAliyunMonitorEcsMetricName.cpu_load),
    );
    const pluginMonitorServerCpu_loadGroupByInstanceId = lodash.groupBy(pluginMonitorServerCpuLoads, value => value.instanceId);

    const ecsList = [] as PluginAliyunMonitorECSDto[];

    for (const pluginMonitorECS of pluginMonitorECSList) {
      const ecs = {} as PluginAliyunMonitorECSDto;
      ecs.instanceId = pluginMonitorECS.instanceId;
      ecs.instanceName = pluginMonitorECS.instanceName;
      ecs.cpu_total = pluginMonitorServerCpu_totalGroupByInstanceId[pluginMonitorECS.instanceId];
      ecs.memory_usedutilization = pluginMonitorServerMemory_usedutilizationGroupByInstanceId[pluginMonitorECS.instanceId];
      ecs.cpu_load = pluginMonitorServerCpu_loadGroupByInstanceId[pluginMonitorECS.instanceId];
      ecs.period = requestDto.period;
      ecsList.push(ecs);
    }
    responseDto.ecs = ecsList;


/*    // SLB
    const pluginAliyunSLBList = await this.pluginAliyunSLBRepository.find({ isMonitor: true });
    const slbQPSList: PluginAliyunMonitorSLB_QPS[] = await this.pluginAliyunMonitorSLBQPSRepository.query(
      await this.packageSql('plugin_aliyun_monitor_slb_qps', requestDto, pluginAliyunSLBList)
      ,
    );
    const slbQPSGroupByInstanceId = lodash.groupBy(slbQPSList, value => value.instanceId);
    const slbList = [] as PluginAliyunMonitorSLBDto[];
    for (const pluginAliyunSLB of pluginAliyunSLBList) {
      const slb = {} as PluginAliyunMonitorSLBDto;
      slb.instanceId = pluginAliyunSLB.instanceId;
      slb.instanceName = pluginAliyunSLB.instanceName;
      slb.qps = slbQPSGroupByInstanceId[pluginAliyunSLB.instanceId];
      slb.period = requestDto.period;
      slbList.push(slb);
    }
    responseDto.slb = slbList;


    // polardb
    const aliyunPolardbList = await this.pluginAliyunPolardbRepository.find({ isMonitor: true });
    const polardbQPSList: PluginAliyunMonitorPolardbMetric[] = await this.pluginAliyunMonitorPolardbQpsRepository.query(
      await this.packageSql(PluginAliyunMonitorPolardbMetric.tableName, requestDto, aliyunPolardbList, 'mean_qps')
      ,
    );
    const polardbQPSGroupByInstanceId = lodash.groupBy(polardbQPSList, value => value.instanceId);

    const polardbCpu_ratioList: PluginAliyunMonitorPolardbMetric[] = await this.pluginAliyunMonitorPolardbQpsRepository.query(
      await this.packageSql(PluginAliyunMonitorPolardbMetric.tableName, requestDto, aliyunPolardbList, 'cpu_ratio')
      ,
    );
    const polardbCpu_ratioGroupByInstanceId = lodash.groupBy(polardbCpu_ratioList, value => value.instanceId);

    const polardbMem_ratioList: PluginAliyunMonitorPolardbMetric[] = await this.pluginAliyunMonitorPolardbQpsRepository.query(
      await this.packageSql(PluginAliyunMonitorPolardbMetric.tableName, requestDto, aliyunPolardbList, 'mem_ratio')
      ,
    );
    const polardbMem_ratioGroupByInstanceId = lodash.groupBy(polardbMem_ratioList, value => value.instanceId);

    const polardbList = [] as PluginAliyunMonitorPolardbDto[];
    for (const pluginAliyunPolardb of aliyunPolardbList) {
      const polardb = {} as PluginAliyunMonitorPolardbDto;
      polardb.instanceId = pluginAliyunPolardb.instanceId;
      polardb.instanceName = pluginAliyunPolardb.instanceName;
      polardb.qps = polardbQPSGroupByInstanceId[pluginAliyunPolardb.instanceId];
      polardb.cpu_ratio = polardbCpu_ratioGroupByInstanceId[pluginAliyunPolardb.instanceId];
      polardb.mem_ratio = polardbMem_ratioGroupByInstanceId[pluginAliyunPolardb.instanceId];
      polardb.period = requestDto.period;
      polardbList.push(polardb);
    }
    responseDto.polardb = polardbList;

    // redis
    const aliyunRedisList = await this.pluginAliyunRedisRepository.find({ isMonitor: true });
    const redisQPSList = await this.pluginAliyunMonitorRedisMetricRepository.query(
      await this.packageSql(PluginAliyunMonitorRedisMetric.tableName, requestDto, aliyunRedisList,
        `'${PluginAliyunMonitorRedisMetricType.TotalQps}','${PluginAliyunMonitorRedisMetricType.GetQps}','${PluginAliyunMonitorRedisMetricType.PutQps}'`),
    );
    const redisQPSListGroupByInstanceId = lodash.groupBy(redisQPSList, value => value.instanceId);


    const redisCpuUsageList = await this.pluginAliyunMonitorRedisMetricRepository.query(
      await this.packageSql(PluginAliyunMonitorRedisMetric.tableName, requestDto, aliyunRedisList,
        `'${PluginAliyunMonitorRedisMetricType.CpuUsage}'`),
    );
    const redisCpuUsageListGroupByInstanceId = lodash.groupBy(redisCpuUsageList, value => value.instanceId);

    const redisUsedMemoryList = await this.pluginAliyunMonitorRedisMetricRepository.query(
      await this.packageSql(PluginAliyunMonitorRedisMetric.tableName, requestDto, aliyunRedisList,
        `'${PluginAliyunMonitorRedisMetricType.MemoryUsage}'`),
    );
    const redisUsedMemoryListGroupByInstanceId = lodash.groupBy(redisUsedMemoryList, value => value.instanceId);

    const redisMetricList = [] as PluginAliyunMonitorRedisMetricDto[];
    for (const aliyunRedis of aliyunRedisList) {
      const redisMetric = {} as PluginAliyunMonitorRedisMetricDto;
      redisMetric.instanceId = aliyunRedis.instanceId;
      redisMetric.instanceName = aliyunRedis.instanceName;
      redisMetric.qps = redisQPSListGroupByInstanceId[aliyunRedis.instanceId];
      redisMetric.cpuUsage = redisCpuUsageListGroupByInstanceId[aliyunRedis.instanceId];
      redisMetric.usedMemory = redisUsedMemoryListGroupByInstanceId[aliyunRedis.instanceId];
      redisMetric.period = requestDto.period;
      redisMetricList.push(redisMetric);
    }
    responseDto.redis = redisMetricList;

    // Rocketmq
    const aliyunRocketmqList = await this.pluginAliyunRocketmqRepository.find({ isMonitor: true });
    const rocketmqConsumerLagList = await this.pluginAliyunMonitorRocketmqMetricRepository.query(
      await this.packageSql(PluginAliyunMonitorRocketmqMetric.tableName, requestDto, aliyunRocketmqList,
        `'${PluginAliyunMonitorRocketmqMetricType.ConsumerLag}'`),
    );
    const rocketmqConsumerLagListGroupByInstanceId = lodash.groupBy(rocketmqConsumerLagList, value => value.instanceId);

    const rocketmqReceiveMessageCountPerInstanceList = await this.pluginAliyunMonitorRocketmqMetricRepository.query(
      await this.packageSql(PluginAliyunMonitorRocketmqMetric.tableName, requestDto, aliyunRocketmqList,
        `'${PluginAliyunMonitorRocketmqMetricType.ReceiveMessageCountPerInstance}'`),
    );
    const rocketmqReceiveMessageCountPerInstanceListGroupByInstanceId = lodash.groupBy(rocketmqReceiveMessageCountPerInstanceList, value => value.instanceId);

    const rocketmqSendMessageCountPerInstanceList = await this.pluginAliyunMonitorRocketmqMetricRepository.query(
      await this.packageSql(PluginAliyunMonitorRocketmqMetric.tableName, requestDto, aliyunRocketmqList,
        `'${PluginAliyunMonitorRocketmqMetricType.SendMessageCountPerInstance}'`),
    );
    const rocketmqSendMessageCountPerInstanceListGroupByInstanceId = lodash.groupBy(rocketmqSendMessageCountPerInstanceList, value => value.instanceId);

    const rocketmqMetricList = [] as PluginAliyunMonitorRocketmqMetricDto[];
    for (const aliyunRocketmq of aliyunRocketmqList) {
      const rocketmqMetric = {} as PluginAliyunMonitorRocketmqMetricDto;
      rocketmqMetric.instanceId = aliyunRocketmq.instanceId;
      rocketmqMetric.instanceName = aliyunRocketmq.instanceName;
      rocketmqMetric.period = requestDto.period;
      rocketmqMetric.consumerLag = rocketmqConsumerLagListGroupByInstanceId[aliyunRocketmq.instanceId];
      rocketmqMetric.receiveMessageCountPerInstance = rocketmqReceiveMessageCountPerInstanceListGroupByInstanceId[aliyunRocketmq.instanceId];
      rocketmqMetric.sendMessageCountPerInstance = rocketmqSendMessageCountPerInstanceListGroupByInstanceId[aliyunRocketmq.instanceId];
      rocketmqMetricList.push(rocketmqMetric);
    }
    responseDto.rocketmq = rocketmqMetricList;*/


    ar.result = responseDto;
    return res.json(ar);
  }

  async packageSql(tableName: string, dto: PluginAliyunMonitorDto, pluginAliyunMonitorInstanceList: PluginAliyunMonitorInstance[], metricName?: string) {
    let dayFormat = '%Y-%m-%d %H:%M:%S';
    let groupBy;
    let sql;
    const current = new Date().getTime();
    let startTime = current - 60 * 60 * 1000;
    if (dto.period === PluginAliyunMonitorPeriod.oneHours) {
      // 每条数据为一组
      groupBy = `strftime('${dayFormat}', datetime(t / 1000, 'unixepoch','localtime'))`;
    } else if (dto.period === PluginAliyunMonitorPeriod.sixHours) {
      dayFormat = '%Y-%m-%d %H:%M';
      startTime = current - 6 * 60 * 60 * 1000;
      // 一分钟为一组
      groupBy = `strftime('${dayFormat}', datetime(t / 1000, 'unixepoch','localtime'))`;
    } else if (dto.period === PluginAliyunMonitorPeriod.oneDay) {
      dayFormat = '%Y-%m-%d %H:%M';
      startTime = current - 24 * 60 * 60 * 1000;
      // 5分组为一组
      groupBy = `strftime('${dayFormat}', datetime(t / 1000 - t / 1000 % 300, 'unixepoch','localtime'))`;
    } else if (dto.period === PluginAliyunMonitorPeriod.sevenDay) {
      dayFormat = '%Y-%m-%d %H:%M';
      startTime = current - 7 * 24 * 60 * 60 * 1000;
      // 15分组为一组
      groupBy = `strftime('${dayFormat}', datetime(t / 1000 - t / 1000 % 900, 'unixepoch','localtime'))`;
    } else if (dto.period === PluginAliyunMonitorPeriod.fifteenDay) {
      dayFormat = '%Y-%m-%d %H:%M';
      startTime = current - 15 * 24 * 60 * 60 * 1000;
      // 15分组为一组
      groupBy = `strftime('${dayFormat}', datetime(t / 1000 - t / 1000 % 900, 'unixepoch','localtime'))`;
    }

    if (tableName === PluginAliyunMonitorEcsMetric.tableName) {
      sql = `select ${groupBy} date,instanceId,instanceName, round(avg(average),2) average,metric
      ${metricName === PluginAliyunMonitorEcsMetricName.cpu_load ? ',type' : ''}
      from ${tableName} where instanceId in (${pluginAliyunMonitorInstanceList.map(value => `'${value.instanceId}'`).join(',')}) 
      and t >= ${startTime} and t < ${current} and metric = '${metricName}'
      group by date,instanceId,metric
      ${metricName === PluginAliyunMonitorEcsMetricName.cpu_load ? ',type' : ''}`;
    } else if (tableName === PluginAliyunMonitorSLB_QPS.tableName) {
      sql = `select ${groupBy} date,instanceId,instanceName, round(avg(average),2) average 
      from ${tableName} where instanceId in (${pluginAliyunMonitorInstanceList.map(value => `'${value.instanceId}'`).join(',')}) 
      and t >= ${startTime} and t < ${current} 
      group by date,instanceId`;
    } else if (tableName === PluginAliyunMonitorPolardbMetric.tableName) {
      sql = `select ${groupBy} date,instanceId,instanceName,nodeId,type,round(avg(average),2) average from ${tableName} where instanceId in (${pluginAliyunMonitorInstanceList.map(value => `'${value.instanceId}'`).join(',')}) 
      and t >= ${startTime} and t < ${current} and type = '${metricName}' group by instanceId,nodeId,type,date`;
    } else if (tableName === PluginAliyunMonitorRedisMetric.tableName) {
      sql = `select ${groupBy} date,instanceId,instanceName,type,round(avg(average),2) average from ${tableName} where instanceId in (${pluginAliyunMonitorInstanceList.map(value => `'${value.instanceId}'`).join(',')}) 
      and t >= ${startTime} and t < ${current} and type in (${metricName}) group by instanceId,type,date`;
    } else if (tableName === PluginAliyunMonitorRocketmqMetric.tableName) {
      sql = `select ${groupBy} date,instanceId,instanceName,type,groupId,round(avg(average),2) average from ${tableName} where instanceId in (${pluginAliyunMonitorInstanceList.map(value => `'${value.instanceId}'`).join(',')}) 
      and t >= ${startTime} and t < ${current} and type in (${metricName}) group by instanceId,type,groupId,date`;
    }


    console.log('metricName sql',sql);
    return sql;
  }

}